#include <iostream>
#include <functional>
#include <vector>
#include <memory>
#include <thread>
#include <future>
#include <mutex>
#include <condition_variable>

const int defaultThreadNum = 3;

class ThreadPool
{
public:
    using TaskFunctor = std::function<void(void)>;
public:
    ThreadPool(int threadNum = defaultThreadNum): _isRunning(true)
    {
        for(int i = 0; i < threadNum; i++) 
        {
            _threads.emplace_back(std::thread(&ThreadPool::threadRoutine, this));
        }
    }

    template<typename F, typename ...Args> //任务函数，参数列表
    auto submit(F&& func, Args&& ...args) -> std::future<decltype(func(args...))> //对不确定返回值类型auto的说明，返回值后置，避免参数未定义
    {
        using funcRetType = decltype(func(args...));
        auto taskFunc = std::bind(std::forward<F>(func), std::forward<Args>(args)...); //std::forward<>：完美转发，传参的过程中维持右值/左值属性，...在括号外边有点搞笑了
        auto ptask = std::make_shared<std::packaged_task<funcRetType(void)>>(taskFunc);
        std::future<funcRetType> fut = ptask->get_future();
        {
            std::unique_lock<std::mutex> lock(_mtx);
            _taskQueue.push_back([ptask]() {
                (*ptask)();
            });
            _cond.notify_one();
        }
        return fut;
    }

    ~ThreadPool()
    {
        _isRunning = false;
        _cond.notify_all();
        for(auto& t : _threads) 
        {
            t.join();
        }
    }
private:
    void threadRoutine()
    {
        while(_isRunning)
        {
            std::vector<TaskFunctor> tasks;
            {
                std::unique_lock<std::mutex> lock(_mtx);
                _cond.wait(lock, [this]() {
                    return !_taskQueue.empty() || !_isRunning; //条件变量收到notify通知后，回调此函数，若返回true，则真正唤醒
                });
                tasks.swap(_taskQueue); //取出任务队列的所有任务

                // while(_isRunning && _taskQueue.empty())
                // {
                //     _cond.wait(lock);
                // }
            }
            for(auto& taskFunctor : tasks)
            {
                taskFunctor();
            }
        }
    }
private:
    std::atomic<bool> _isRunning;
    std::vector<TaskFunctor> _taskQueue;
    std::mutex _mtx;
    std::condition_variable _cond;
    std::vector<std::thread> _threads;
};